JavaPOI导出Excel有三种形式,他们分别是
1.HSSFWorkbook
2.XSSFWorkbook
3.SXSSFWorkbook。
HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls;
XSSFWorkbook:是操作Excel2007后的版本,扩展名是.xlsx;
SXSSFWorkbook:是操作Excel2007后的版本,扩展名是.xlsx;
第一种:HSSFWorkbook
poi导出excel最常用的方式;但是此种方式的局限就是导出的行数至多为65535行,超出65536条后系统就会报错。此方式因为行数不足七万行所以一般不会发生内存不足的情况(OOM)。
第二种:XSSFWorkbook
这种形式的出现是为了突破HSSFWorkbook的65535行局限。其对应的是excel2007(1048576行,16384列)扩展名为“.xlsx”,最多可以导出104万行,不过这样就伴随着一个问题---OOM内存溢出,原因是你所创建的book sheet row cell等此时是存在内存的并没有持久化。
第三种:SXSSFWorkbook
从POI 3.8版本开始,提供了一种基于XSSF的低内存占用的SXSSF方式。对于大型excel文件的创建,一个关键问题就是,要确保不会内存溢出。其实,就算生成很小的excel(比如几Mb),它用掉的内存是远大于excel文件实际的size的。如果单元格还有各种格式(比如,加粗,背景标红之类的),那它占用的内存就更多了。对于大型excel的创建且不会内存溢出的,就只有SXSSFWorkbook了。它的原理很简单,用硬盘空间换内存(就像hash map用空间换时间一样)。
SXSSFWorkbook是streaming版本的XSSFWorkbook,它只会保存最新的excel rows在内存里供查看,在此之前的excel rows都会被写入到硬盘里(Windows电脑的话,是写入到C盘根目录下的temp文件夹)。被写入到硬盘里的rows是不可见的/不可访问的。只有还保存在内存里的才可以被访问到。
原有的导出excel方式采用的是HSSFWorkbook方式,经测试当选择的高度很多时,生成ecxel的列很多,无法生成excel,页面一直等待进程无法结束;
然后改用XSSFWorkbook方式,此方式当写入的行和列很多时比较耗内存,有时出现无法生成excel的现象;
最后选择SXSSFWorkbook方式,经测试此种方式生成excel文件速度较快,内存消耗较少,生成27M的文件大概用时2S左右,生成55M的文件大概用时4S左右,生成85M的文件大概用时9S左右可以满足需求;
最终决定选用SXSSFWorkbook方式生成Excel文件;
第一组数据导出测试
数据量10月一整月数据,高度间隔7.5m,最大高度6000m,因子数三因子(消光、退偏、颗粒物),常规方式读取;读取处理数据用时208s,生成excel用时81s,生成文件大小496M;
修改成多sheet模式
10月整月数据,高度间隔7.5m,最大高度6000m,三因子,读取用时208s,生成用时52s,生成文件大小475M;
10月1号到7号数据导出,间隔7.5m,最大高度6000m,三因子,读取50s,生成用时8s,
文件大小98M;
10月整月数据,单因子导出,间隔7.5m,最大高度6000m,读取142s,生成用时11s,文件大小143M
方法改良
原有的方法为先读取雷达数据到一个jsonObject中,然后在把jsonObject中的数据生成excel对象,这种方式消耗的内存较大;改良后每读取一条数据生成一条excel记录,该方式消耗内存较少,生成excel速度优于原有方式,所以采用新方式生成excel
新方式:
10月整月数据导出,高度间隔7.5,最大高度6000m,单因子,总用时31s,比原方式快122s,生成文件大小143M
12000m,导出用时96s,单因子,导出文件大小241M
显示导出进度问题
1、通过在session中存导出进度的方式,经测试该方式严重影响导出效率;
2、通过在redis中存导出进度的方式,经测试该方式相比在session中导出效率有所提高,但还是不理想
3、最终决定把数据最大分成100份,然后最多设置100个进度值,经测试导出效率大大提升,接近不使用进度的效果,故采用此方式解决;
停止导出问题
当点击导出停止时,出现空页面的现象;解决方案:通过返回一个空的excel对象来解决,最终会生成一个空的excel;
解决方式二:
通过window.location.href = window.location.href对页面进行刷新来解决返回空的excel问题,此方式会明显感觉到页面的刷新体验不好;
解决方式三:
通过创建iframe的方式解决
var elemIF = document.createElement('iframe');
elemIF.src = url;
elemIF.style.display = 'none';
document.body.appendChild(elemIF);
此方式完美解决了导出停止时的空excel对象问题;
最后把iframe移除document.body.removeChild(elemIF);
//冻结第一行第一列
sheet.createFreezePane(1, 1, 1, 1);